﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.InteropServices;

namespace CHomeWeather
{
    public static class Util
    {
        public const int HWND_BROADCAST = 0xFFFF;
        public const int WM_WININICHANGE = 0x001A;
        public const string APP_RUN_AT_TIME = "AppRunAtTime";

        private const string ABSOLUTE_PATH_PREFIX = "\\";

        private class SystemTime
        {
            public short Year;
            public short Month;
            public short DayOfWeek;
            public short Day;
            public short Hour;
            public short Minute;
            public short Second;
            public short MilliSecond;
        }

        /// <summary>
        /// Initializes a new instance of <see cref="Util"/>.
        /// </summary>
        static Util()
        {
            string codebase = Assembly.GetExecutingAssembly().GetName().CodeBase;
            ApplicationFolder = Path.GetDirectoryName(codebase);
        }

        [DllImport("coredll.dll")]
        public static extern int SendMessage(IntPtr hWnd, uint msg, int wParam, int lParam);

        [DllImport("coredll.dll", EntryPoint = "CeRunAppAtTime", SetLastError = true)]
        private static extern bool CeRunAppAtTime(string appName, SystemTime lpTime);

        /// <summary>
        /// Gets the application folder.
        /// </summary>
        public static string ApplicationFolder { get; private set; }

        public static bool RunApplicationAtTime(string applicationName, DateTime time)
        {
            SystemTime systemTime = new SystemTime();

            if (DateTime.MinValue != time)
            {
                systemTime.Year = (short)time.Year;
                systemTime.Month = (short)time.Month;
                systemTime.DayOfWeek = (short)time.DayOfWeek;
                systemTime.Day = (short)time.Day;
                systemTime.Hour = (short)time.Hour;
                systemTime.Minute = (short)time.Minute;
                systemTime.Second = (short)time.Second;
                systemTime.MilliSecond = (short)time.Millisecond;
            }

            return CeRunAppAtTime(applicationName, systemTime);
        }

        /// <summary>
        /// Gets a value indicates whether a file path is absolute path.
        /// </summary>
        public static bool IsAbsolutePath(string path)
        {
            return (!string.IsNullOrEmpty(path) && path.StartsWith(ABSOLUTE_PATH_PREFIX));
        }

        public static void RefreshToday()
        {
            Util.SendMessage((IntPtr)Util.HWND_BROADCAST, Util.WM_WININICHANGE, 0xF2, 0);
        }

        public static void Update(bool updateAutoRun)
        {
            Configuration configuration = Configuration.Load(Configuration.CONFIGURATION_FILE_NAME);

            Template template = Template.Load(configuration.Template);

            UpdateService service = new UpdateService(template, configuration);
            service.Update();

            RefreshToday();

            if (updateAutoRun)
            {
                SetNextUpdateTime(configuration);
            }
        }

        public static void SetNextUpdateTime(Configuration configuration)
        {
            if (null == configuration || null == configuration.Schedules)
            {
                return;
            }

            List<DateTime> updateTimes = new List<DateTime>();

            foreach (var schedule in configuration.Schedules)
            {
                DateTime updateTime = schedule.UpdateTime;

                if (Occurrence.Once == schedule.Occurrence && updateTime > DateTime.Now)
                {
                    updateTimes.Add(updateTime);
                }
                else if (Occurrence.Daily == schedule.Occurrence)
                {
                    updateTime = DateTime.Now.Date + updateTime.TimeOfDay;

                    if (updateTime > DateTime.Now)
                    {
                        updateTimes.Add(updateTime);
                    }
                    else
                    {
                        updateTimes.Add(updateTime.AddDays(1));
                    }
                }
            }

            if (0 < updateTimes.Count)
            {
                updateTimes.Sort();

                DateTime firstUpdate = updateTimes[0];

                Util.RunApplicationAtTime(Assembly.GetExecutingAssembly().GetName().CodeBase, firstUpdate);
            }
            else
            {
                Util.RunApplicationAtTime(Assembly.GetExecutingAssembly().GetName().CodeBase, DateTime.MinValue);
            }
        }
    }
}
